<template>
  <div class="base64-converter">
    <div class="header">
      <h2>Base64和文件互转</h2>
      <p>支持文件转Base64编码，以及Base64解码为文件</p>
    </div>

    <div class="converter-container">
      <!-- 文件转Base64 -->
      <div class="section">
        <h3>文件转Base64</h3>
        <div class="file-upload">
          <input 
            type="file" 
            ref="fileInput" 
            @change="handleFileSelect" 
            class="file-input"
            id="file-input"
          />
          <label for="file-input" class="file-label">
            <svg class="upload-icon" viewBox="0 0 24 24">
              <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" />
            </svg>
            {{ selectedFile ? selectedFile.name : '选择文件' }}
          </label>
        </div>
        
        <div v-if="selectedFile" class="file-info">
          <p><strong>文件名:</strong> {{ selectedFile.name }}</p>
          <p><strong>文件大小:</strong> {{ formatFileSize(selectedFile.size) }}</p>
          <p><strong>文件类型:</strong> {{ selectedFile.type || '未知' }}</p>
        </div>

        <button 
          @click="convertFileToBase64" 
          :disabled="!selectedFile || converting"
          class="convert-btn"
        >
          {{ converting ? '转换中...' : '转换为Base64' }}
        </button>

        <div v-if="base64Result" class="result-section">
          <h4>Base64结果:</h4>
          <textarea 
            v-model="base64Result" 
            readonly 
            class="result-textarea"
            placeholder="Base64编码结果将显示在这里"
          ></textarea>
          <div class="result-actions">
            <button @click="copyToClipboard(base64Result)" class="action-btn">
              复制Base64
            </button>
            <button @click="downloadBase64" class="action-btn">
              下载Base64文件
            </button>
          </div>
        </div>
      </div>

      <!-- Base64转文件 -->
      <div class="section">
        <h3>Base64转文件</h3>
        <div class="input-group">
          <label for="file-type">文件类型:</label>
          <input 
            type="text" 
            id="file-type"
            v-model="outputFileType" 
            placeholder="例如: image/png, text/plain, application/pdf"
            class="file-type-input"
          />
        </div>
        
        <div class="input-group">
          <label for="file-name">文件名:</label>
          <input 
            type="text" 
            id="file-name"
            v-model="outputFileName" 
            placeholder="例如: output.png, document.txt"
            class="file-name-input"
          />
        </div>

        <textarea 
          v-model="base64Input" 
          class="base64-input"
          placeholder="请粘贴Base64编码内容..."
        ></textarea>

        <button 
          @click="convertBase64ToFile" 
          :disabled="!base64Input.trim() || converting"
          class="convert-btn"
        >
          {{ converting ? '转换中...' : '转换为文件' }}
        </button>
      </div>
    </div>

    <!-- 提示消息 -->
    <div v-if="message" :class="['message', messageType]">
      {{ message }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { writeFile, BaseDirectory } from '@tauri-apps/plugin-fs'

const selectedFile = ref<File | null>(null)
const base64Result = ref('')
const base64Input = ref('')
const outputFileType = ref('')
const outputFileName = ref('')
const converting = ref(false)
const message = ref('')
const messageType = ref<'success' | 'error'>('success')
const fileInput = ref<HTMLInputElement>()

// 处理文件选择
const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files && target.files[0]) {
    selectedFile.value = target.files[0]
    base64Result.value = ''
  }
}

// 格式化文件大小
const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 文件转Base64
const convertFileToBase64 = async () => {
  if (!selectedFile.value) return
  
  converting.value = true
  try {
    const reader = new FileReader()
    reader.onload = (e) => {
      if (e.target?.result) {
        base64Result.value = e.target.result as string
        showMessage('文件转换为Base64成功！', 'success')
      }
    }
    reader.onerror = () => {
      showMessage('文件读取失败', 'error')
    }
    reader.readAsDataURL(selectedFile.value)
  } catch (error) {
    showMessage('转换失败: ' + (error as Error).message, 'error')
  } finally {
    converting.value = false
  }
}

// Base64转文件
const convertBase64ToFile = async () => {
  if (!base64Input.value.trim()) return
  
  converting.value = true
  try {
    let base64Data = base64Input.value.trim()
    
    // 移除data URL前缀（如果存在）
    if (base64Data.startsWith('data:')) {
      const commaIndex = base64Data.indexOf(',')
      if (commaIndex !== -1) {
        base64Data = base64Data.substring(commaIndex + 1)
      }
    }
    
    // 解码Base64
    const binaryString = atob(base64Data)
    const bytes = new Uint8Array(binaryString.length)
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i)
    }
    
    // 生成文件名
    const fileName = outputFileName.value || `converted_${Date.now()}.bin`
    
    // 使用Tauri保存文件
    await writeFile(fileName, bytes, {
      baseDir: BaseDirectory.Download
    })
    
    showMessage(`文件已保存到下载目录: ${fileName}`, 'success')
  } catch (error) {
    showMessage('转换失败: ' + (error as Error).message, 'error')
  } finally {
    converting.value = false
  }
}

// 复制到剪贴板
const copyToClipboard = async (text: string) => {
  try {
    await navigator.clipboard.writeText(text)
    showMessage('已复制到剪贴板', 'success')
  } catch (error) {
    showMessage('复制失败', 'error')
  }
}

// 下载Base64文件
const downloadBase64 = async () => {
  if (!base64Result.value || !selectedFile.value) return
  
  try {
    const fileName = `${selectedFile.value.name}.base64.txt`
    const encoder = new TextEncoder()
    const data = encoder.encode(base64Result.value)
    
    await writeFile(fileName, data, {
      baseDir: BaseDirectory.Download
    })
    
    showMessage(`Base64文件已保存到下载目录: ${fileName}`, 'success')
  } catch (error) {
    showMessage('下载失败: ' + (error as Error).message, 'error')
  }
}

// 显示消息
const showMessage = (msg: string, type: 'success' | 'error') => {
  message.value = msg
  messageType.value = type
  setTimeout(() => {
    message.value = ''
  }, 3000)
}
</script>

<style scoped>
.base64-converter {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.header {
  text-align: center;
  margin-bottom: 30px;
}

.header h2 {
  color: #2c3e50;
  margin-bottom: 10px;
}

.header p {
  color: #7f8c8d;
  font-size: 14px;
}

.converter-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  margin-bottom: 20px;
}

@media (max-width: 768px) {
  .converter-container {
    grid-template-columns: 1fr;
  }
}

.section {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e9ecef;
}

.section h3 {
  color: #2c3e50;
  margin-bottom: 20px;
  font-size: 18px;
}

.file-upload {
  margin-bottom: 15px;
}

.file-input {
  display: none;
}

.file-label {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  background: #fff;
  border: 2px dashed #3498db;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s ease;
  color: #3498db;
  font-weight: 500;
}

.file-label:hover {
  background: #f8f9fa;
  border-color: #2980b9;
}

.upload-icon {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.file-info {
  background: #fff;
  padding: 15px;
  border-radius: 6px;
  margin-bottom: 15px;
  border: 1px solid #e9ecef;
}

.file-info p {
  margin: 5px 0;
  font-size: 14px;
  color: #495057;
}

.input-group {
  margin-bottom: 15px;
}

.input-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: 500;
  color: #495057;
}

.file-type-input,
.file-name-input {
  width: 100%;
  padding: 10px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  font-size: 14px;
}

.file-type-input:focus,
.file-name-input:focus {
  outline: none;
  border-color: #3498db;
  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
}

.base64-input,
.result-textarea {
  width: 100%;
  min-height: 150px;
  padding: 12px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  font-size: 12px;
  resize: vertical;
  margin-bottom: 15px;
}

.base64-input:focus,
.result-textarea:focus {
  outline: none;
  border-color: #3498db;
  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
}

.convert-btn {
  width: 100%;
  padding: 12px;
  background: #3498db;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.convert-btn:hover:not(:disabled) {
  background: #2980b9;
}

.convert-btn:disabled {
  background: #bdc3c7;
  cursor: not-allowed;
}

.result-section {
  margin-top: 20px;
}

.result-section h4 {
  color: #2c3e50;
  margin-bottom: 10px;
}

.result-actions {
  display: flex;
  gap: 10px;
}

.action-btn {
  flex: 1;
  padding: 8px 16px;
  background: #27ae60;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.action-btn:hover {
  background: #219a52;
}

.message {
  padding: 12px 20px;
  border-radius: 6px;
  margin-top: 20px;
  font-weight: 500;
}

.message.success {
  background: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

.message.error {
  background: #f8d7da;
  color: #721c24;
  border: 1px solid #f5c6cb;
}
</style>